//
// Created by Xiaoyun on 2023/3/22.
//

#include <errno.h>
#include <sys/times.h>
#include <stdint.h>
#include <string.h>
#include "retarget.h"

#if !defined(OS_USE_SEMIHOSTING)

#define STDIN_FILENO  0
#define STDOUT_FILENO 1
#define STDERR_FILENO 2

UART_HandleTypeDef *gHuart;
static uint8_t Usart1DMARecBuffer[USART1_DMA_REC_SIZE]; // DMA 接收数组

__weak void USART_RXCallback(uint8_t* data,uint16_t size){
  printf("%d\r\n%s",size,data);
}

static void start_usart_dma_rx(UART_HandleTypeDef *huart){
  HAL_UARTEx_ReceiveToIdle_DMA(gHuart,Usart1DMARecBuffer,USART1_DMA_REC_SIZE);
  __HAL_DMA_DISABLE_IT(huart->hdmarx,DMA_IT_HT);
}

void RetargetInit(UART_HandleTypeDef *huart)
{
  gHuart = huart;
  
  /* Disable I/O buffering for STDOUT stream, so that
   * chars are sent out as soon as they are printed. */
  setvbuf(stdout, NULL, _IONBF, 0);

  // start one DMA_Receive
  start_usart_dma_rx(huart);
}

void HAL_UARTEx_RxEventCallback(UART_HandleTypeDef *huart, uint16_t Size)
{
  if(huart -> Instance == USART1){
    USART_RXCallback(Usart1DMARecBuffer,Size);
    memset(Usart1DMARecBuffer,0x00,Size);
    start_usart_dma_rx(huart);
  }
}

void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){
  HAL_UARTEx_RxEventCallback(huart,USART1_DMA_REC_SIZE);
}

void HAL_UART_ErrorCallback(UART_HandleTypeDef *huart){
  start_usart_dma_rx(huart);
}


int _isatty(int fd)
{
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
    return 1;
  
  errno = EBADF;
  return 0;
}

int _write(int fd, char *ptr, int len)
{
  HAL_StatusTypeDef hstatus;
  
  if (fd == STDOUT_FILENO || fd == STDERR_FILENO)
  {
    hstatus = HAL_UART_Transmit(gHuart, (uint8_t *) ptr, len,HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return len;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}

int _close(int fd)
{
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
    return 0;
  
  errno = EBADF;
  return -1;
}

int _lseek(int fd, int ptr, int dir)
{
  (void) fd;
  (void) ptr;
  (void) dir;
  
  errno = EBADF;
  return -1;
}

int _read(int fd, char *ptr, int len)
{
  HAL_StatusTypeDef hstatus;
  
  if (fd == STDIN_FILENO)
  {
    hstatus = HAL_UART_Receive(gHuart, (uint8_t *) ptr, 1, HAL_MAX_DELAY);
    if (hstatus == HAL_OK)
      return 1;
    else
      return EIO;
  }
  errno = EBADF;
  return -1;
}

int _fstat(int fd, struct stat *st)
{
  if (fd >= STDIN_FILENO && fd <= STDERR_FILENO)
  {
    st->st_mode = S_IFCHR;
    return 0;
  }
  
  errno = EBADF;
  return 0;
}

#endif //#if !defined(OS_USE_SEMIHOSTING)